//题目:
// 给你一个整数数组 coins ，表示不同面额的硬币；以及一个整数 amount ，表示总金额。
// 计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额，返回 -1 。
// 你可以认为每种硬币的数量是无限的。

// 示例 1：
// 输入：coins = [1, 2, 5], amount = 11
// 输出：3 
// 解释：11 = 5 + 5 + 1

// 示例 2:
// 输入：coins = [2], amount = 3
// 输出：-1

// 示例 3：
// 输入：coins = [1], amount = 0
// 输出：0
#include<iostream>
#include<vector>

using namespace std;

//代码:
class Solution 
{
public:
    int coinChange(vector<int>& coins, int amount) 
    {
        //完全背包问题
        //1.创建dp表————dp[i][j]表示：coins[0] ~ coins[i] 区间中，组成和为 j 的最少硬币个数
        // int n=coins.size();
        // vector<vector<int>> dp(n+1,vector<int>(amount+1,0x3f3f3f3f));
        // //2.初始化
        // dp[0][0]=0;
        // //3.动态转移方程————dp[i][j] = min(dp[i-1][j],dp[i-1][j-coins[i]])
        // for(int i=1;i<=n;i++)
        // {
        //     for(int j=0;j<=amount;j++)
        //     {
        //         dp[i][j]=dp[i-1][j];
        //         if(j-coins[i-1]>=0)
        //             dp[i][j]=min(dp[i][j],dp[i][j-coins[i-1]]+1);
        //     }
        // }
        // //4.确定返回值
        // return dp[n][amount]==0x3f3f3f3f?-1:dp[n][amount];

        //空间优化
        int n=coins.size();
        vector<int> dp(amount+1,0x3f3f3f3f);
        //2.初始化
        dp[0]=0;
        //3.动态转移方程————dp[i][j] = min(dp[i-1][j],dp[i-1][j-coins[i]])
        for(int i=1;i<=n;i++)
            for(int j=coins[i-1];j<=amount;j++)
                dp[j]=min(dp[j],dp[j-coins[i-1]]+1);
        //4.确定返回值
        return dp[amount]==0x3f3f3f3f?-1:dp[amount];
    }
};
